
let source_filename, reduce =
  let reduce_ref = ref false in
  let source_ref = ref None in
  let set_source_file s = source_ref := Some s in
  let _ =
    Arg.parse
      ["--reduce", Arg.Set reduce_ref, " Reduce normal form";
       "--", Arg.Rest set_source_file, " Stop interpreting arguments"]
      set_source_file
      "Usage: minimize OPTIONS filename"
  in
    match !source_ref with
	None -> assert false (* ERROR *)
      | Some s -> s, !reduce_ref

let string_of_state a p =
  Printf.sprintf "q_{%d}" (Builder.A.get_state_index a p)

let string_of_simple_nf_state a p =
  Printf.sprintf "q_{%d}" (Builder.A_fnr.get_state_index a p)

let string_of_state_min a pset =
  if Builder.A_fnr.StateSet.is_empty pset then
    "\\emptyset"
  else
    "\\{" ^ String.concat "," (List.map (string_of_simple_nf_state a) (Builder.A_fnr.StateSet.elements pset)) ^ "\\}"

let string_of_state_set a pset =
  if Builder.A.StateSet.is_empty pset then
    "\\emptyset"
  else
    "\\{" ^ String.concat "," (List.map (string_of_state a) (Builder.A.StateSet.elements pset)) ^ "\\}"

let string_of_action action =
  let name = String.sub action 1 (String.length action - 1) in
    match action.[0] with
	'?' -> name
      | '!' -> "\\overline{" ^ name ^ "}"
      | _ -> assert false (* IMPOSSIBLE *)

let string_of_transition =
  function
      Automaton.Transition.Tau -> "\\tau"
    | Automaton.Transition.Action action -> string_of_action action

let string_of_ready_set rset =
  if Builder.A.ReadySet.is_empty rset then
    "\\emptyset"
  else
    "\\{" ^ String.concat "," (List.map string_of_action (Builder.A.ReadySet.elements rset)) ^ "\\}"

let string_of_acceptance_set aset =
  if Builder.A.AcceptanceSet.is_empty aset then
    "\\emptyset"
  else
    "\\{" ^ String.concat "," (List.map string_of_ready_set (Builder.A.AcceptanceSet.elements aset)) ^ "\\}"

let string_of_nf_state a (pset, aset) =
  "(" ^ string_of_state_set a pset ^ "," ^ string_of_acceptance_set aset ^ ")"

let make_graph to_graph a name =
  let ch = open_out (name ^ ".dot") in
    to_graph ch a name;
    close_out ch

let _ =
  let basename = Filename.basename source_filename in
  let name = Filename.chop_extension basename in
  let lexbuf = Lexing.from_channel (open_in source_filename) in
  let activity = Parser.main Lexer.token lexbuf in
  let t0 = Sys.time () in
  let a = Builder.make_automaton activity in
  let t1 = Sys.time () in
  let q0, b = Builder.make_automaton_fnr reduce a activity in
  let t2 = Sys.time () in
  let r0, c = Builder.minimize b q0 in
  let t3 = Sys.time () in
    Printf.printf "\
building     : %.3fs (%d states)\n\
normal form  : %.3fs (%d states)\n\
minimization : %.3fs (%d states)\n"
      (t1 -. t0) (Builder.A.size a)
      (t2 -. t1) (Builder.A_fnr.size b)
      (t3 -. t2) (Builder.A_min.size c);
    make_graph
      (Builder.A.to_graph "circle" (string_of_state a) string_of_transition)
      a (name ^ ".A");
    make_graph
      (Builder.A_fnr.to_graph "circle" (string_of_simple_nf_state b) string_of_transition)
      b (name ^ ".B");
    make_graph
      (Builder.A_min.to_graph "circle" (string_of_state_min b) string_of_transition)
      c (name ^ ".C");
    flush stdout
